﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Romeo.WinForms;
using System.Diagnostics;

namespace Romeo.Data
{
    public class Evaluation
    {
        private Evaluator _Evaluator;
        private Board _Board;
        private int _Evaluation;
        private int _Cell;
        public int _MinEval = Int32.MinValue;

        public Evaluation (Evaluator aEvaluator, Board aBoard, int aCell)
        {
            _Evaluator = aEvaluator;
            _Board = new Board (aBoard, "move to " + aCell.ToString ());
            _Cell = aCell;
            Debug.Print ("Created evaluation for " + _Board._Name);
        }

        public int Execute ()
        {
            Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
            Debug.Print ("Starting evaluation for " + _Board._Name + " on " + Thread.CurrentThread.ManagedThreadId.ToString());
            _Evaluation = _Evaluator.Evaluate (_Board, _MinEval);
            Debug.Print ("Done evaluation for " + _Board._Name + " on " + Thread.CurrentThread.ManagedThreadId.ToString ());
            return _Evaluation;
        }

        public int Score
        {
            get
            {
                return _Evaluation;
            }
        }

        public int Cell
        {
            get
            {
                return _Cell;
            }
        }

        public Evaluator Evaluator
        {
            get
            {
                return _Evaluator;
            }
        }
    }

    public class BestMoveStrategy : Strategy
    {
        private int[] _Moves = new int[] {
            /* corners */11, 18, 81, 88,
            /* border out */13, 31, 16, 61, 83, 38, 86, 68,
            /* border in */14, 41, 15, 51, 84, 48, 85, 58,
            /* inner ring */33, 63, 66, 36, 34, 43, 35, 53, 64, 46, 65, 56,
            /* outer ring */32, 23, 62, 26, 37, 73, 67, 76, 24, 42, 74, 47, 25, 52, 75, 57,
            /* border worst */12, 21, 17, 71, 28, 82, 78, 87,
            /* worst */22, 77, 72, 27 };


        private List<Evaluation> _Pending = new List<Evaluation> ();
        private List<Evaluation> _Executing = new List<Evaluation> ();

        private SynchronizationContext _Sync;
        private int _BestMove;
        private int _BestScore;
        private Board _Board;
        public int MaxLevel = 2;

        public Evaluator GetEvaluator ()
        {
            Evaluator _LockEval = new LockedCellEvaluator ();
            Evaluator _FrontEval = new FrontierEvaluator ();
            Evaluator _StatEval = new StaticScoreEvaluator ( 50, -15,  20,  15, 
                                                                 -30, -10,  -5, 
                                                                        5,   3, 
                                                                             1);
            Evaluator CombEval = new CombinedEvaluator (_LockEval, _FrontEval, _StatEval);
            return new MinimaxEvaluator (MaxLevel, CombEval);
        }

        protected void DoReportSelected ()
        {
            OnMoveSelected (new CellEventArgs (_Board, _BestMove));
        }

        private void ScheduleOne ()
        {
            Evaluation ev = _Pending[0];
            _Pending.Remove (ev);
            _Executing.Add (ev);
            ev._MinEval = _BestScore;
            ThreadPool.QueueUserWorkItem (EvaluateAndReport, ev);
        }

        private void ScheduleSome ()
        {
            while (_Executing.Count < 8 && _Pending.Count > 0)
            {
                ScheduleOne ();
            }
        }

        private void ReportDone (Object aEvaluation)
        {
            Evaluation ev = aEvaluation as Evaluation;
            _Executing.Remove (ev);
            AddStatistics (ev.Evaluator);        
            if (ev.Score > _BestScore)
            {
                _BestScore = ev.Score;
                _BestMove = ev.Cell;
                DoReportBestSoFar (_Board, _BestMove);
            }

            ScheduleSome ();

            if (_Pending.Count == 0 && _Executing.Count == 0)
            {
                DoReportSelected ();
            }
        }

        private void EvaluateAndReport (Object aEvaluation)
        {
            Evaluation ev = aEvaluation as Evaluation;
            ev.Evaluator.ResetStatistics ();
            ev.Execute ();
            _Sync.Post (ReportDone, ev);
        }
        public override void Compute (Board aStartingPosition)
        {
            ResetStatistics ();
            _Board = aStartingPosition;
            _BestMove = 0;
            _BestScore = Int32.MinValue;

            _Pending.Clear ();
            _Sync = SynchronizationContext.Current;

            foreach (int cell in _Moves)
            {
                Move m = aStartingPosition.PlayOn (cell, Board.Computer);
                if (m != null)
                {
                    Evaluation ev = new Evaluation (GetEvaluator (), aStartingPosition, cell);
                    _Pending.Add (ev);
                    aStartingPosition.Undo (m);
                }
            }
            if (_Pending.Count > 0)
            {
                ScheduleSome ();
            }
            else
            {
                DoReportSelected ();
            }
        }

    }
}
